﻿using CK.Sprite.CrossCutting;
using CK.Sprite.StackExchangeRedis;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using StackExchange.Redis;
using System.Collections.Generic;
using System.Linq;

namespace CK.Sprite.Cache.Redis
{
    /// <summary>
    /// Redis缓存容器通知服务
    /// </summary>
    public class RedisCacheSendNotice : ICacheSendNotice
    {
        private readonly SpriteConfig _callHttpConfig;
        private readonly IDistributedCache _distributedCache;
        private readonly ISubscriber _subscriber;

        public RedisCacheSendNotice(IDistributedCache distributedCache, IOptions<SpriteConfig> callHttpConfig)
        {
            _distributedCache = distributedCache;
            _callHttpConfig = callHttpConfig.Value;
            var spriteRedisCache = _distributedCache as SpriteRedisCache;
            spriteRedisCache.RedisDatabase.Multiplexer.ConnectionFailed += Multiplexer_ConnectionFailed;
            spriteRedisCache.RedisDatabase.Multiplexer.ConnectionRestored += Multiplexer_ConnectionRestored;
            _subscriber = spriteRedisCache.RedisDatabase.Multiplexer.GetSubscriber();

            if (_callHttpConfig.RemoteReceivePreKey != null)
            {
                foreach (var remoteReceivePreKey in _callHttpConfig.RemoteReceivePreKey)
                {
                    _subscriber.Subscribe(remoteReceivePreKey, (channel, message) =>
                    {
                        ReceiveCacheNotice.ReceiveClearCache(message);
                    });

                    _subscriber.Subscribe($"{remoteReceivePreKey}s", (channel, message) =>
                    {
                        List<string> keys = JsonConvert.DeserializeObject<List<string>>(message);
                        ReceiveCacheNotice.ReceiveClearCaches(keys);
                    });
                }
            }
        }

        private void Multiplexer_ConnectionRestored(object sender, StackExchange.Redis.ConnectionFailedEventArgs e)
        {
            ReceiveCacheNotice.SetLocalCacheIsEnabled(true);
        }

        private void Multiplexer_ConnectionFailed(object sender, StackExchange.Redis.ConnectionFailedEventArgs e)
        {
            ReceiveCacheNotice.SetLocalCacheIsEnabled(false);
        }

        public void SendClearCache(string key)
        {
            ReceiveCacheNotice.ReceiveClearCache(key);
            if (_callHttpConfig.RemoteNoticePreKey != null)
            {
                if (_callHttpConfig.RemoteNoticePreKey.Any(r => key.StartsWith($"{r}-")))
                {
                    _subscriber.Publish(key.Split('-')[0], key);
                }
            }
        }

        public void SendClearCaches(List<string> keys)
        {
            ReceiveCacheNotice.ReceiveClearCaches(keys);
            if (_callHttpConfig.RemoteNoticePreKey != null)
            {
                var groupKeyLists = keys.GroupBy(r => r.Split('-')[0]);
                foreach (var groupKeyList in groupKeyLists)
                {

                    if (_callHttpConfig.RemoteNoticePreKey.Any(r => groupKeyList.Key == r))
                    {
                        _subscriber.Publish($"{groupKeyList.Key}s", JsonConvert.SerializeObject(groupKeyList.ToList()));
                    }
                }
            }
        }
    }
}
